package com.coldlz.mmp.ssl;

import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.bc.BcX509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;

import javax.security.auth.x500.X500Principal;
import java.io.IOException;
import java.security.*;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;

public class CertificateInfoHelper {

    public static AuthorityKeyIdentifier getAuthorityKeyIdentifier(X509Certificate cert) {
        X509CertificateHolder rootCertHolder = null;
        try {
            rootCertHolder = new X509CertificateHolder(cert.getEncoded());
        } catch (IOException | CertificateEncodingException e) {
            throw new RuntimeException(e);
        }
        AuthorityKeyIdentifier authorityKeyIdentifier = new BcX509ExtensionUtils().createAuthorityKeyIdentifier(rootCertHolder);
        byte[] keyIdentifier = authorityKeyIdentifier.getKeyIdentifier();
        return new AuthorityKeyIdentifier(keyIdentifier);
    }

    public static X500Name getIssuer(X509Certificate rootCert) {
        String rootIssuer = rootCert.getSubjectX500Principal().getName(X500Principal.RFC1779);
        Map<ASN1ObjectIdentifier, String> x500NameBuilderParams = new HashMap<>(8);
        for (String item : rootIssuer.split(" ")) {
            String[] arr = item.split("=");
            String name = arr[0];
            String value = arr[1];
            if (value.endsWith(",")) {
                value = value.substring(0, value.length() - 1);
            }
            switch (name) {
                case "C" -> x500NameBuilderParams.put(BCStyle.C, value);
                case "ST" -> x500NameBuilderParams.put(BCStyle.ST, value);
                case "L" -> x500NameBuilderParams.put(BCStyle.L, value);
                case "O" -> x500NameBuilderParams.put(BCStyle.O, value);
                case "OU" -> x500NameBuilderParams.put(BCStyle.OU, value);
                case "CN" -> x500NameBuilderParams.put(BCStyle.CN, value);
                case "OID.1.2.840.113549.1.9.1" -> x500NameBuilderParams.put(BCStyle.E, value);
            }
        }
        X500NameBuilder x500NameBuilder = new X500NameBuilder(X500Name.getDefaultStyle());
//            x500NameBuilderParams.forEach(x500NameBuilder::addRDN);
        // 必须是下面的这个顺序，不知道为啥，反正直接使用 x500NameBuilderParams.forEach(x500NameBuilder::addRDN); 浏览器不认
        x500NameBuilder.addRDN(BCStyle.C, x500NameBuilderParams.get(BCStyle.C));
        x500NameBuilder.addRDN(BCStyle.ST, x500NameBuilderParams.get(BCStyle.ST));
        x500NameBuilder.addRDN(BCStyle.L, x500NameBuilderParams.get(BCStyle.L));
        x500NameBuilder.addRDN(BCStyle.O, x500NameBuilderParams.get(BCStyle.O));
        x500NameBuilder.addRDN(BCStyle.OU, x500NameBuilderParams.get(BCStyle.OU));
        x500NameBuilder.addRDN(BCStyle.CN, x500NameBuilderParams.get(BCStyle.CN));
        x500NameBuilder.addRDN(BCStyle.E, x500NameBuilderParams.get(BCStyle.E));
        return x500NameBuilder.build();
    }

    public static X509Certificate signature(X509v3CertificateBuilder certBuilder, KeyPairStr keyPairStr)
            throws IOException, CertificateException, OperatorCreationException, NoSuchAlgorithmException, SignatureException, InvalidKeyException, NoSuchProviderException {
        AlgorithmIdentifier certSigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA512withRSA");
        AlgorithmIdentifier certDigAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(certSigAlgId);
        AsymmetricKeyParameter privateKeyParameter = PrivateKeyFactory.createKey(keyPairStr.getPrivateKey());
        ContentSigner certSigner = new BcRSAContentSignerBuilder(certSigAlgId, certDigAlgId).build(privateKeyParameter);
        X509CertificateHolder holder = certBuilder.build(certSigner);
        X509Certificate cert = new JcaX509CertificateConverter().getCertificate(holder);
        cert.verify(keyPairStr.getPublic());
        return cert;
    }
}
